/**
 * Copyright 2007-2010 非也
 * All rights reserved. 
 * 
 * This library is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License v3 as published by the Free Software
 * Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along
 * with this library; if not, see http://www.gnu.org/licenses/lgpl.html.
 *
 */
package org.fireflow2.designer.eclipse.properties.service.human;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.namespace.QName;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TrayDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.FilteredResourcesSelectionDialog;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.fireflow.model.AbstractModelElement;
import org.fireflow.model.data.Expression;
import org.fireflow.model.data.Input;
import org.fireflow.model.data.impl.ExpressionImpl;
import org.fireflow.model.data.impl.InputImpl;
import org.fireflow.model.servicedef.InterfaceDef;
import org.fireflow.model.servicedef.OperationDef;
import org.fireflow.model.servicedef.impl.CommonInterfaceDef;
import org.fireflow.model.servicedef.impl.OperationDefImpl;
import org.fireflow.service.human.HumanService;
import org.fireflow2.designer.eclipse.modelwrapper.basic.ServiceDefWrapper;
import org.fireflow2.designer.eclipse.properties.service.AbstractServiceEditPanel;
import org.fireflow2.designer.eclipse.util.Util4Eclipse;
import org.firesoa.common.schema.NameSpaces;
import org.firesoa.common.util.ScriptLanguages;

/**
 * 
 * @author 非也 nychen2000@163.com Fire Workflow 官方网站：www.firesoa.com 或者
 *         www.fireflow.org
 * 
 */
public class HumanServiceEditPanel extends AbstractServiceEditPanel {
	private static final List<QName> BASIC_JAVA_DATATYPES = new ArrayList<QName>();
	static {
		BASIC_JAVA_DATATYPES.add(new QName(NameSpaces.JAVA.getUri(),
				"java.lang.String", NameSpaces.JAVA.getPrefix()));
		// BASIC_JAVA_DATATYPES.add(new
		// QName(NameSpaces.JAVA.getUri(),"java.util.Date",NameSpaces.JAVA.getPrefix()));
		BASIC_JAVA_DATATYPES.add(new QName(NameSpaces.JAVA.getUri(), "int",
				NameSpaces.JAVA.getPrefix()));
		BASIC_JAVA_DATATYPES.add(new QName(NameSpaces.JAVA.getUri(), "boolean",
				NameSpaces.JAVA.getPrefix()));
		BASIC_JAVA_DATATYPES.add(new QName(NameSpaces.JAVA.getUri(), "float",
				NameSpaces.JAVA.getPrefix()));
		BASIC_JAVA_DATATYPES.add(new QName(NameSpaces.JAVA.getUri(), "double",
				NameSpaces.JAVA.getPrefix()));
		BASIC_JAVA_DATATYPES.add(new QName(NameSpaces.JAVA.getUri(), "short",
				NameSpaces.JAVA.getPrefix()));
		BASIC_JAVA_DATATYPES.add(new QName(NameSpaces.JAVA.getUri(), "long",
				NameSpaces.JAVA.getPrefix()));
		// BASIC_JAVA_DATATYPES.add(new
		// QName(NameSpaces.JAVA.getUri(),"byte[]",NameSpaces.JAVA.getPrefix()));

	}
	Text nameText = null;
	Text displayNameText = null;
	Text formURLText = null;
	TableViewer formURLParameterTableViewer = null;
	Text workItemSubjectText = null;

	public HumanServiceEditPanel() {

	}

	public HumanServiceEditPanel(ServiceDefWrapper svcDefWrapper) {
		super(svcDefWrapper);
	}

	protected void addInput(Input input) {
		HumanService humanService = (HumanService) this.getServiceDefWrapper()
				.getWorkflowModelElement();
		InterfaceDef _interface = humanService.getInterface();
		final OperationDef operation = _interface.getOperations().get(0);
		operation.getInputs().add(input);
	}

	protected void removeInput(Input input) {
		HumanService humanService = (HumanService) this.getServiceDefWrapper()
				.getWorkflowModelElement();
		InterfaceDef _interface = humanService.getInterface();
		final OperationDef operation = _interface.getOperations().get(0);
		operation.getInputs().remove(input);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.fireflow2.designer.eclipse.properties.service.AbstractServiceEditPanel
	 * #createControl(org.eclipse.swt.widgets.Composite)
	 */
	@Override
	public Control createControl(final Composite contentPane) {

		FormToolkit formToolkit = new FormToolkit(Display.getCurrent());

		GridLayout layout = new GridLayout(3, false);
		contentPane.setLayout(layout);

		GridData gridData = null;
		gridData = new GridData(GridData.FILL_HORIZONTAL);
		gridData.horizontalSpan = 2;

		// 表单URL
		Label formUrlLabel = formToolkit.createLabel(contentPane, "表单URL：");
		formUrlLabel.setBackground(contentPane.getBackground());
		formURLText = formToolkit.createText(contentPane, "");
		gridData = new GridData(GridData.FILL_HORIZONTAL);
		gridData.horizontalSpan = 1;
		formURLText.setLayoutData(gridData);
		formURLText.addModifyListener(new ModifyListener() {

			public void modifyText(ModifyEvent e) {
				updateServiceProperty("FORM_URL");
			}

		});
		Button searchJspButton = formToolkit.createButton(contentPane, "...",
				SWT.PUSH);
		searchJspButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				FilteredResourcesSelectionDialog selectionDialog = new FilteredResourcesSelectionDialog(
						contentPane.getShell(), false, getServiceDefWrapper()
								.getProject(), IResource.FILE);
				// SelectionDialog selectionDialog = JavaUI.createTypeDialog(
				// parent.getShell(),
				// PlatformUI.getWorkbench().getProgressService(),getServiceDefWrapper().getProject()
				// , IJavaElementSearchConstants.CONSIDER_CLASSES, false);
				//
				int returnCode = selectionDialog.open();
				if (returnCode == Dialog.OK) {
					Object[] fileList = selectionDialog.getResult();
					if (fileList != null && fileList.length > 0) {
						Object obj = fileList[0];
						if (obj instanceof IFile) {
							IFile file = (IFile) obj;

							formURLText.setText(file.getFullPath().toString());
						}
					}

				}

			}
		});

		// URL参数列表
		Label formURLParameterLabel = formToolkit.createLabel(contentPane,
				"URL参数：");
		formURLParameterLabel.setBackground(contentPane.getBackground());
		formURLParameterTableViewer = new TableViewer(contentPane, SWT.MULTI
				| SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION);
		Table table = formURLParameterTableViewer.getTable();
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
		gridData = new GridData(GridData.FILL_BOTH);
		gridData.horizontalSpan = 1;
		table.setLayoutData(gridData);

		final String[] columnNames = new String[] { "参数名称", "中文名", "类型" };
		int[] columnAlignments = new int[] { SWT.LEFT, SWT.LEFT, SWT.LEFT };
		for (int i = 0; i < columnNames.length; i++) {
			TableColumn tableColumn = new TableColumn(table,
					columnAlignments[i]);
			tableColumn.setText(columnNames[i]);
			if (i == 0)
				tableColumn.setWidth(100);
			if (i == 1)
				tableColumn.setWidth(100);
			if (i == 2)
				tableColumn.setWidth(200);
		}

		Composite buttonPanel_1 = formToolkit.createComposite(contentPane);
		buttonPanel_1.setBackground(contentPane.getBackground());
		gridData = new GridData();
		gridData.horizontalSpan = 1;
		gridData.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING;
		buttonPanel_1.setLayoutData(gridData);
		formURLParameterTableViewer
				.setContentProvider(new ArrayContentProvider());
		formURLParameterTableViewer
				.setLabelProvider(new MyTableLabelProvider());

		buttonPanel_1.setLayout(new GridLayout(1, false));
		Button addUrlParameterButton = formToolkit.createButton(buttonPanel_1,
				"+", SWT.PUSH);
		addUrlParameterButton.setToolTipText("增加URL参数");
		addUrlParameterButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				AddInputDialog dialog = new AddInputDialog(contentPane
						.getShell(), null);
				int returnCode = dialog.open();
				if (returnCode == Dialog.OK) {
					Input input = dialog.getResult();
					addInput(input);
					refreshUI();
					firePropertyModifyEvent(true, "",
							"INPUT", "1", "0");
				}
			}
		});

		Button deleteUrlParameterButton = formToolkit.createButton(
				buttonPanel_1, "-", SWT.PUSH);
		deleteUrlParameterButton.setToolTipText("删除选中的URL参数");
		deleteUrlParameterButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				ISelection selection = formURLParameterTableViewer
						.getSelection();
				if (selection != null && !selection.isEmpty()) {
					StructuredSelection tmp = (StructuredSelection) selection;
					Iterator it = tmp.iterator();
					while (it.hasNext()) {
						Input input = (Input) it.next();
						removeInput(input);

					}
				}
				refreshUI();
				firePropertyModifyEvent(true, "",
						"INPUT", "1", "0");
			}
		});

		// 工作项主题表达式
		Label workItemSubjectLabel = formToolkit.createLabel(contentPane,
				"工作项主题表达式：", SWT.WRAP);
		workItemSubjectLabel.setBackground(contentPane.getBackground());
		gridData = new GridData();
		gridData.horizontalSpan = 1;
		gridData.widthHint = 60;
		workItemSubjectLabel.setLayoutData(gridData);

		workItemSubjectText = formToolkit.createText(contentPane, "", SWT.MULTI
				| SWT.BORDER);
		gridData = new GridData(GridData.FILL_BOTH);
		gridData.horizontalSpan = 1;
		workItemSubjectText.setLayoutData(gridData);
		workItemSubjectText.addModifyListener(new ModifyListener() {

			public void modifyText(ModifyEvent e) {
				updateServiceProperty("WORKITEM_SUBJECT");
			}

		});

		Button insertVarButton = formToolkit.createButton(contentPane, "Var",
				SWT.PUSH);
		insertVarButton.setToolTipText("插入流程变量到表达式中");

		// 服务名和中文名
		gridData = new GridData(GridData.FILL_HORIZONTAL);
		gridData.horizontalSpan = 2;

		Label nameLabel = formToolkit.createLabel(contentPane, "服务名：");
		nameLabel.setBackground(contentPane.getBackground());
		nameText = formToolkit.createText(contentPane, "");
		nameText.setLayoutData(gridData);
		nameText.addModifyListener(new ModifyListener() {

			public void modifyText(ModifyEvent e) {
				updateServiceProperty("NAME");
			}

		});

		Label displayNameLabel = formToolkit.createLabel(contentPane, "中文名：");
		displayNameLabel.setBackground(contentPane.getBackground());
		displayNameText = formToolkit.createText(contentPane, "");
		displayNameText.setLayoutData(gridData);
		displayNameText.addModifyListener(new ModifyListener() {

			public void modifyText(ModifyEvent e) {
				updateServiceProperty("DISPLAY_NAME");
			}

		});

		return contentPane;
	}

	public void refreshUI() {
		HumanService humanService = (HumanService) this.getServiceDefWrapper()
				.getWorkflowModelElement();
		InterfaceDef _interface = humanService.getInterface();
		final OperationDef operation = _interface.getOperations().get(0);

		formURLParameterTableViewer.setInput(operation.getInputs());

		nameText.setText(humanService.getName()==null?"":humanService.getName());
		displayNameText.setText(humanService.getDisplayName()==null?"":humanService.getDisplayName());
		formURLText.setText(humanService.getFormUrl()==null?"":humanService.getFormUrl());
		Expression wiSubject = humanService.getWorkItemSubject();
		String body = wiSubject == null ? "" : wiSubject.getBody();
		workItemSubjectText.setText(body == null ? "" : body);
	}

	protected void updateServiceProperty(String propertyName) {
		HumanService humanSvc = (HumanService) this.getServiceDefWrapper()
				.getWorkflowModelElement();
		if (humanSvc == null) {
			return;
		}
		CommonInterfaceDef _interface = (CommonInterfaceDef) humanSvc
				.getInterface();
		if (_interface == null) {
			_interface = new CommonInterfaceDef();
			humanSvc.setInterface(_interface);
		}

		OperationDefImpl operation = null;
		List<OperationDef> operationList = _interface.getOperations();
		if (operationList == null || operationList.size() == 0) {
			operation = new OperationDefImpl();
			operationList.add(operation);
		} else {
			operation = (OperationDefImpl) operationList.get(0);
		}
		
		// workitemsubject
		ExpressionImpl exp = (ExpressionImpl) humanSvc.getWorkItemSubject();
		if (exp == null) {
			exp = new ExpressionImpl();
			exp.setLanguage(ScriptLanguages.UNIFIEDJEXL.name());
			exp.setDataType(new QName(NameSpaces.JAVA.getUri(), String.class
					.getName(), NameSpaces.JAVA.getPrefix()));
			exp.setName("WorkItemSubject");
			exp.setDisplayName("工作项主题");// 需国际化
			exp.setBody("");
			humanSvc.setWorkItemSubject(exp);
		}

		boolean propertyIsOK = true;
		String errorMessage = null;
		Object newValue = null;
		Object oldValue = null;

		// 检查类名是否合法
		if (propertyName.equals("NAME") && !Util4Eclipse.strEquals(nameText.getText(), humanSvc.getName())) {
			if (nameText.getText() == null
					|| nameText.getText().trim().equals("")) {
				propertyIsOK = false;
				errorMessage = "服务名不能为空。";
				this.firePropertyModifyEvent(propertyIsOK, errorMessage,
						propertyName, "", humanSvc.getName());
				return;
			} else {
				if (!AbstractModelElement.isValidName(nameText.getText())) {
					propertyIsOK = false;
					errorMessage = "服务名不合法，服务名必须符合变量名命名规范。";
					this.firePropertyModifyEvent(propertyIsOK, errorMessage,
							propertyName, nameText.getText(), humanSvc.getName());
					return;
				}

				propertyIsOK = true;
				newValue = nameText.getText();
				oldValue = humanSvc.getName();

				humanSvc.setName(nameText.getText());
				_interface.setName(nameText.getText());

				this.firePropertyModifyEvent(propertyIsOK, errorMessage,
						propertyName, newValue, oldValue);
				return;
			}
		}

		// displayName
		
		else if (propertyName.equals("DISPLAY_NAME") && !Util4Eclipse.strEquals(displayNameText.getText(), humanSvc.getDisplayName())) {
			String displayName = displayNameText.getText();
			newValue = displayName;
			oldValue = humanSvc.getDisplayName();
			propertyIsOK = true;

			humanSvc.setDisplayName(displayName);
			if (displayName == null || displayName.trim().equals("")) {
				operation.setOperationName("打开表单：" + nameText.getText());
			} else {
				operation.setOperationName("打开表单：" + displayName);
			}
			
			this.firePropertyModifyEvent(propertyIsOK, errorMessage,
					propertyName, newValue, oldValue);
			return;
		}

		// Form URL
		else if (propertyName.equals("FORM_URL")
				&& !Util4Eclipse.strEquals(formURLText.getText(),
						humanSvc.getFormUrl())) {
			String formUrl = formURLText.getText();

			if (formUrl == null || formUrl.trim().equals("")) {
				propertyIsOK = false;
				errorMessage = "表单URL不能为空";
				this.firePropertyModifyEvent(propertyIsOK, errorMessage,
						propertyName, "", humanSvc.getFormUrl());
				return;
			} else {
				oldValue = humanSvc.getFormUrl();
				newValue = formUrl;
				propertyIsOK = true;

				humanSvc.setFormUrl(formUrl);

				this.firePropertyModifyEvent(propertyIsOK, errorMessage,
						propertyName, newValue, oldValue);
				return;
			}

		}
		else if (propertyName.equals("WORKITEM_SUBJECT")
				&& !Util4Eclipse.strEquals(exp.getBody(),
				workItemSubjectText.getText())) {
			oldValue = exp.getBody();
			newValue = workItemSubjectText.getText();
			propertyIsOK = true;

			exp.setBody(workItemSubjectText.getText());
			
			this.firePropertyModifyEvent(propertyIsOK, errorMessage,
					propertyName, newValue, oldValue);
			return;
		}
	}

	class MyTableLabelProvider extends LabelProvider implements
			ITableLabelProvider {
		public Image getColumnImage(Object element, int index) {
			return null;
		}

		public String getColumnText(Object element, int index) {
			Input input = (Input) element;

			switch (index) {
			case 0:
				return input.getName();
			case 1:
				return input.getDisplayName();
			case 2:
				QName dataType = input.getDataType();

				return (dataType == null ? "" : dataType.getPrefix() + ":"
						+ dataType.getLocalPart());

			default:
				return "unknown " + index;
			}
		}
	}

	class AddInputDialog extends TrayDialog {
		Input input = null;

		Label messageLabel = null;
		Text parameterNameText = null;
		Text parameterDisplayNameText = null;
		ComboViewer dataTypeComboBox = null;

		/**
		 * @param parentShell
		 */
		protected AddInputDialog(Shell parentShell, Input argInput) {
			super(parentShell);
			setShellStyle(getShellStyle() | SWT.TITLE);
			input = argInput;
			if (input == null) {
				input = new InputImpl();
				input.setName("param1");
				input.setDisplayName("参数1");
				input.setDataType(new QName(NameSpaces.JAVA.getUri(),
						"java.lang.String", NameSpaces.JAVA.getPrefix()));
			}
		}

		public Input getResult() {
			return input;
		}

		protected void configureShell(Shell newShell) {
			super.configureShell(newShell);
			newShell.setText("新增URL参数");

		}

		protected Control createDialogArea(Composite parent) {
			Composite contentPane = (Composite) super.createDialogArea(parent);

			contentPane.setLayout(new GridLayout(2, false));
			GridData gridData = new GridData(GridData.FILL_HORIZONTAL);

			messageLabel = new Label(contentPane, SWT.NONE);
			gridData = new GridData(GridData.FILL_HORIZONTAL);
			gridData.horizontalSpan = 2;
			messageLabel.setLayoutData(gridData);
			messageLabel.setForeground(ColorConstants.red);

			gridData = new GridData(GridData.FILL_HORIZONTAL);

			Label parameterNameLabel = new Label(contentPane, SWT.NONE);
			parameterNameLabel.setText("参数名：");

			parameterNameText = new Text(contentPane, SWT.BORDER);
			parameterNameText.setLayoutData(gridData);
			parameterNameText.addModifyListener(new ModifyListener() {

				public void modifyText(ModifyEvent e) {
					updateInput();
				}

			});

			Label parameterDisplayNameLabel = new Label(contentPane, SWT.NONE);
			parameterDisplayNameLabel.setText("中文名：");

			parameterDisplayNameText = new Text(contentPane, SWT.BORDER);
			parameterDisplayNameText.setLayoutData(gridData);
			parameterDisplayNameText.addModifyListener(new ModifyListener() {

				public void modifyText(ModifyEvent e) {
					updateInput();
				}

			});

			Label dataTypeCombobox = new Label(contentPane, SWT.None);
			dataTypeCombobox.setText("数据类型");

			dataTypeComboBox = new ComboViewer(contentPane, SWT.DROP_DOWN
					| SWT.READ_ONLY | SWT.SINGLE);
			dataTypeComboBox.setContentProvider(new ArrayContentProvider());
			dataTypeComboBox.setLabelProvider(new LabelProvider() {
				public String getText(Object element) {
					QName qname = (QName) element;
					return element == null ? "" : qname.getPrefix() + ":" + qname.getLocalPart();//$NON-NLS-1$
				}
			});
			dataTypeComboBox.setInput(BASIC_JAVA_DATATYPES);
			dataTypeComboBox.getControl().setLayoutData(gridData);
			dataTypeComboBox
					.addSelectionChangedListener(new ISelectionChangedListener() {

						public void selectionChanged(SelectionChangedEvent event) {
							updateInput();

						}

					});

			// 初始化数据
			parameterDisplayNameText.setText(input.getDisplayName());
			parameterNameText.setText(input.getName());
			StructuredSelection tmp = new StructuredSelection(
					input.getDataType());
			dataTypeComboBox.setSelection(tmp);

			return contentPane;
		}

		private void updateInput() {
			Button button = getButton(IDialogConstants.OK_ID);
			String name = parameterNameText.getText();
			if (!AbstractModelElement.isValidName(name)) {
				this.setErrorMessage("参数名字必须符合变量名规范。");
				if (button != null)
					button.setEnabled(false);
				return;
			} else {
				input.setName(name);
			}
			String displayName = parameterDisplayNameText.getText();
			if (displayName == null || displayName.trim().equals("")) {
				this.setErrorMessage("中文名不能为空。");
				if (button != null)
					button.setEnabled(false);
				return;
			} else {
				input.setDisplayName(displayName);
			}

			ISelection selection = dataTypeComboBox.getSelection();
			if (selection == null || selection.isEmpty()) {
				this.setErrorMessage("数据类型不能为空。");
				if (button != null)
					button.setEnabled(false);
				return;
			} else {
				StructuredSelection tmp = (StructuredSelection) selection;
				input.setDataType((QName) tmp.getFirstElement());
			}
			this.setErrorMessage(null);

			if (button != null)
				button.setEnabled(true);
		}

		private void setErrorMessage(String msg) {
			if (msg == null) {
				messageLabel.setText("");
				return;
			}
			messageLabel.setText(msg);
		}

	}
}
